﻿#include "MLibraryV0.h"

using namespace ManagedSquish;

namespace LibraryEditor
{

bool MLibraryV0::Load = true;

    MLibraryV0::MLibraryV0(const std::string &filename)
    {
        FileName = filename;
        Initialize();
        Close();
    }

    void MLibraryV0::Initialize()
    {
        _initialized = true;

        if (!FileSystem::fileExists(FileName))
        {
            return;
        }

        _stream = new FileStream(FileName, FileMode::Open, FileAccess::ReadWrite);
        _reader = new BinaryReader(_stream);

        Count = _reader->ReadInt32();
        Images = std::vector<MImage*>();
        IndexList = std::vector<int>();

        for (int i = 0; i < Count; i++)
        {
            IndexList.push_back(_reader->ReadInt32());
        }

        for (int i = 0; i < Count; i++)
        {
            Images.push_back(nullptr);
        }
        Load = false; //dont need to process all images when converting
        for (int i = 0; i < Count; i++)
        {
            CheckImage(i);
        }
    }

    void MLibraryV0::Close()
    {
        if (_stream != nullptr)
        {
            _stream->Dispose();
        }
        // if (_reader != null)
        //     _reader.Dispose();
    }

    void MLibraryV0::Save()
    {
        Close();

        MemoryStream *stream = new MemoryStream();
        BinaryWriter *writer = new BinaryWriter(stream);

        Count = Images.size();
        IndexList.clear();

        int offSet = 4 + Count * 4;
        for (int i = 0; i < Count; i++)
        {
            IndexList.push_back(static_cast<int>(stream->Length) + offSet);
            Images[i]->Save(writer);
        }

        writer->Flush();
        std::vector<unsigned char> fBytes = stream->ToArray();
        //  writer.Dispose();

        _stream = File::Create(FileName);
        writer = new BinaryWriter(_stream);

        writer->Write(Count);
        for (int i = 0; i < Count; i++)
        {
            writer->Write(IndexList[i]);
        }

        writer->Write(fBytes);
        writer->Flush();
        writer->Close();
        writer->Dispose();
        Close();

//C# TO C++ CONVERTER TODO TASK: A 'delete writer' statement was not added since writer was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete stream' statement was not added since stream was passed to a method or constructor. Handle memory management manually.
    }

    void MLibraryV0::CheckImage(int index)
    {
        if (!_initialized)
        {
            Initialize();
        }

        if (Images.empty() || index < 0 || index >= Images.size())
        {
            return;
        }

        if (Images[index] == nullptr)
        {
            _stream->Position = IndexList[index];
            Images[index] = new MImage(_reader);
        }

        if (!Load)
        {
            return;
        }

        MImage *mi = Images[index];
        if (!mi->TextureValid)
        {
            _stream->Seek(IndexList[index] + 12, SeekOrigin::Begin);
            mi->CreateTexture(_reader);
        }
    }

    Point *MLibraryV0::GetOffSet(int index)
    {
        if (!_initialized)
        {
            Initialize();
        }

        if (Images.empty() || index < 0 || index >= Images.size())
        {
            return Point::Empty;
        }

        if (Images[index] == nullptr)
        {
            _stream->Seek(IndexList[index], SeekOrigin::Begin);
            Images[index] = new MImage(_reader);
        }

        return new Point(Images[index]->X, Images[index]->Y);
    }

    Size *MLibraryV0::GetSize(int index)
    {
        if (!_initialized)
        {
            Initialize();
        }
        if (Images.empty() || index < 0 || index >= Images.size())
        {
            return Size::Empty;
        }

        if (Images[index] == nullptr)
        {
            _stream->Seek(IndexList[index], SeekOrigin::Begin);
            Images[index] = new MImage(_reader);
        }

        return new Size(Images[index]->Width, Images[index]->Height);
    }

    MLibraryV0::MImage *MLibraryV0::GetMImage(int index)
    {
        if (index < 0 || index >= Images.size())
        {
            return nullptr;
        }

        return Images[index];
    }

    Bitmap *MLibraryV0::GetPreview(int index)
    {
        if (index < 0 || index >= Images.size())
        {
            return new Bitmap(1, 1);
        }

        MImage *image = Images[index];

        if (image == nullptr || image->Image == nullptr)
        {
            return new Bitmap(1, 1);
        }

        if (image->Preview == nullptr)
        {
            image->CreatePreview();
        }

        return image->Preview;
    }

    void MLibraryV0::AddImage(Bitmap *image, short x, short y)
    {
        MImage *mImage = new MImage(image);
        mImage->X = x;
        mImage->Y = y;

        Count++;
        Images.push_back(mImage);

//C# TO C++ CONVERTER TODO TASK: A 'delete mImage' statement was not added since mImage was passed to a method or constructor. Handle memory management manually.
    }

    void MLibraryV0::InsertImage(int index, Bitmap *image, short x, short y)
    {
        MImage *mImage = new MImage(image);
        mImage->X = x;
        mImage->Y = y;

        Count++;
        Images.Insert(index, mImage);

//C# TO C++ CONVERTER TODO TASK: A 'delete mImage' statement was not added since mImage was passed to a method or constructor. Handle memory management manually.
    }

    void MLibraryV0::RemoveImage(int index)
    {
        if (Images.empty() || Count <= 1)
        {
            Count = 0;
            Images = std::vector<MImage*>();
            return;
        }
        Count--;

        Images.erase(Images.begin() + index);
    }

    bool MLibraryV0::CompareBytes(std::vector<unsigned char> &a, std::vector<unsigned char> &b)
    {
        if (a == b)
        {
            return true;
        }

        if (a.empty() || b.empty() || a.size() != b.size())
        {
            return false;
        }

        for (int i = 0; i < a.size(); i++)
        {
            if (a[i] != b[i])
            {
                return false;
            }
        }

        return true;
    }

    void MLibraryV0::RemoveBlanks(bool safe)
    {
        for (int i = Count - 1; i >= 0; i--)
        {
            if (Images[i]->FBytes.empty() || Images[i]->FBytes.size() <= 8)
            {
                if (!safe)
                {
                    RemoveImage(i);
                }
                else if (Images[i]->X == 0 && Images[i]->Y == 0)
                {
                    RemoveImage(i);
                }
            }
        }
    }

    MLibraryV0::MImage::MImage(BinaryReader *reader)
    {
        Width = reader->ReadInt16();
        Height = reader->ReadInt16();
        X = reader->ReadInt16();
        Y = reader->ReadInt16();
        Length = reader->ReadInt32();

        FBytes = reader->ReadBytes(Length);
    }

    void MLibraryV0::MImage::Save(BinaryWriter *writer)
    {
        writer->Write(Width);
        writer->Write(Height);
        writer->Write(X);
        writer->Write(Y);

        writer->Write(FBytes.size());
        writer->Write(FBytes);
    }

    void MLibraryV0::MImage::CreatePreview()
    {
        if (Image == nullptr)
        {
            Preview = new Bitmap(1, 1);
            return;
        }

        Preview = new Bitmap(64, 64);

//C# TO C++ CONVERTER NOTE: The following 'using' block is replaced by its C++ equivalent:
//ORIGINAL LINE: using (Graphics g = Graphics.FromImage(Preview))
        {
            Graphics g = Graphics::FromImage(Preview);
            g.InterpolationMode = InterpolationMode::HighQualityBicubic;
            g.Clear(Color::Transparent);
            int w = std::min(static_cast<int>(Width), 64);
            int h = std::min(static_cast<int>(Height), 64);

            Rectangle tempVar((64 - w) / 2, (64 - h) / 2, w, h);
            Rectangle tempVar2(0, 0, Width, Height);
            g.DrawImage(Image, &tempVar, &tempVar2, GraphicsUnit::Pixel);
            g.Save();
        }
    }
}
